﻿using System;
using System.Web;
using System.Web.Mvc;
using MugenInjection.Interface;

namespace MugenInjection.Web.Mvc
{
    /// <summary>
    /// Base implementation of <see cref="HttpApplication"/> that adds injection support.
    /// </summary>
    public abstract class MugenInjectionHttpApplication : HttpApplication
    {
        #region Fields

        private static IInjector _injector;
        private readonly object _locker = new object();

        #endregion

        #region Method

        /// <summary>
        /// Starts the application.
        /// </summary>
        public void Application_Start()
        {
            lock (this)
            {
                Injector = CreateInjector();
                var injectionControllerFactory = new MugenInjectionControllerFactory(Injector);
#if MVC2
                ControllerBuilder.Current.SetControllerFactory(injectionControllerFactory);
#else
                Injector.Bind<IControllerFactory>().ToConstant(injectionControllerFactory);
                DependencyResolver.SetResolver(new MugenInjectionDependencyResolver(Injector));
#endif
                OnApplicationStarted();
            }
        }

        /// <summary>
        /// Releases the kernel on application end.
        /// </summary>
        public void Application_End()
        {
            lock (_locker)
            {
                Injector.Dispose();
                OnApplicationStopped();
            }
        }

        #endregion

        #region Property

        internal static IInjector Injector
        {
            get
            {
                if (_injector == null)
                    throw new NullReferenceException("Injector not initialized.");
                return _injector;
            }
            private set { _injector = value; }
        }

        #endregion
        
        #region Abstract or virtual

        /// <summary>
        /// Creates the injector that will manage your application.
        /// </summary>
        /// <returns>The created injector.</returns>
        protected abstract IInjector CreateInjector();

        /// <summary>
        /// Called when the application is started.
        /// </summary>
        protected virtual void OnApplicationStarted()
        {
        }

        /// <summary>
        /// Called when the application is stopped.
        /// </summary>
        protected virtual void OnApplicationStopped()
        {
        }

        #endregion
    }
}